package com.chen.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chen.reggie.common.R;
import com.chen.reggie.dto.DishDto;
import com.chen.reggie.dto.SetmealDto;
import com.chen.reggie.pojo.Category;
import com.chen.reggie.pojo.Dish;
import com.chen.reggie.pojo.Setmeal;
import com.chen.reggie.pojo.SetmealDish;
import com.chen.reggie.service.CategoryService;
import com.chen.reggie.service.DishService;
import com.chen.reggie.service.SetmealDishService;
import com.chen.reggie.service.SetmealService;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.lang.model.element.VariableElement;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName SetmealController
 * @Description TODO
 * @Author hainc
 * @Date 2022/9/6 8:44
 * @Version 1.0
 * 套装管理
 **/
@RestController
@RequestMapping("/setmeal")
@Slf4j
@Api(tags = "套餐管理接口")
public class SetmealController {

    @Autowired
    private SetmealService setmealService;

    @Autowired
    private SetmealDishService setmealDishService;

    @Autowired
    private DishService dishService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedisTemplate redisTemplate;


    //新增套餐，还要保存套餐和菜品的关系
    @ApiOperation("新增套餐")
    @ApiImplicitParams(
            @ApiImplicitParam(name = "setmealDto",value = "套餐dto对象",required = true)
    )
    @PostMapping
    @CacheEvict(value = "setmealCache",allEntries = true)
    public R<String> saveSetmealDish(@RequestBody SetmealDto setmealDto) {
        log.info("套餐信息：{}", setmealDto);

        setmealService.saveWithDish(setmealDto);

        return R.success("套餐新增成功");
    }

    //根据条件查询套餐分页
    @ApiOperation("根据条件查询套餐分页")
    @GetMapping("/page")
    public R<Page> setmealPage(@ApiParam("页码") int page, @ApiParam("页大小") int pageSize, @ApiParam("查询条件") String name) {
        Page<Setmeal> pageInfo = new Page<>(page, pageSize);
        Page<SetmealDto> setmealDtoPage = new Page<>();

        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotEmpty(name), Setmeal::getName, name);
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);
        //查询分页
        setmealService.page(pageInfo, queryWrapper);
        //对象拷贝
        BeanUtils.copyProperties(pageInfo, setmealDtoPage, "records");
        List<Setmeal> records = pageInfo.getRecords();
        List<SetmealDto> list = records.stream().map((item) -> {
            //每次new dto是防止对象内容覆盖，list集合保存不能是同个对象，不然对象内容会互相影响
            SetmealDto setmealDto = new SetmealDto();
            //1.用dto代替setmeal，首先拷贝setmeal基本信息
            BeanUtils.copyProperties(item, setmealDto);
            Long categoryId = item.getCategoryId();
            Category category = categoryService.getById(categoryId);
            if (category != null) {
                //2. 然后根据setmeal获取的categoryid查询分类名称，赋值给dto对象，基本内容拷贝完成
                setmealDto.setCategoryName(category.getName());
            }
            //返回dto对象
            return setmealDto;
        }).collect(Collectors.toList());//把每个dto转为list返回

        //保存records数据
        setmealDtoPage.setRecords(list);

        return R.success(setmealDtoPage);
    }

    //删除套餐，关联操作
    @ApiOperation("删除套餐")
    @CacheEvict(value = "setmealCache",allEntries = true) //allEntries=true代表删除setmealCache类下的所有缓存，如setmealCahce_1,setmealCache_2...
    @DeleteMapping
    public R<String> deleteSetmeal(@ApiParam("传递的id集合")@RequestParam List<Long> ids) {
        log.info("套餐ids信息：{}", ids);
        setmealService.removeWithDish(ids);
        return R.success("套餐数据删除成功");
    }

    //批量停售
    @PostMapping("/status/{status}")
    @ApiOperation("批量停售")
    public R<String> updateSetmealStatus(@ApiParam("销售状态")@PathVariable int status,@ApiParam("传递的id集合") @RequestParam List<Long> ids) {
        LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
        setmealLambdaQueryWrapper.in(Setmeal::getId, ids);
        Setmeal setmeal = new Setmeal();
        if (status == 1) {//代表需要起售
            setmeal.setStatus(1);
        } else {
            setmeal.setStatus(0);
        }

        setmealService.update(setmeal, setmealLambdaQueryWrapper);

        return R.success("批量停售成功");
    }

    //根据套餐查询菜品集合  , 传递过来的数据是键值对形式，不是json所以实体类前面不需要加@requestBody注解
    @ApiOperation("根据套餐查询菜品集合")
    @Cacheable(value = "setmealCache",key = "#setmeal.categoryId + '_' + #setmeal.status",unless = "#result==null")
    @GetMapping("/list")
    public R<List<Setmeal>> DishList(@ApiParam("套餐") Setmeal setmeal){
        log.info("对象数据：{}",setmeal);
        List<Setmeal> list = null;


        //将套餐存redis中
        //先获取redis中的数据，如果不存在，则查询数据库
//        String key = "setmeal_"+setmeal.getCategoryId()+"_"+setmeal.getStatus();
//        list = (List<Setmeal>) redisTemplate.opsForValue().get(key);

        if(list != null){
            //redis中套餐数据不为空，直接返回redis的套餐缓存数据
            return R.success(list);
        }

        LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
        setmealLambdaQueryWrapper.eq(setmeal.getCategoryId()!=null,Setmeal::getCategoryId,setmeal.getCategoryId());
        setmealLambdaQueryWrapper.eq(setmeal.getStatus()!=null,Setmeal::getStatus,setmeal.getStatus());
        setmealLambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);

        //套餐关联的菜品集合
        list = setmealService.list(setmealLambdaQueryWrapper);
        //并将套餐信息保存到redis中,60分钟
//        redisTemplate.opsForValue().set(key,list,60, TimeUnit.MINUTES);

        return R.success(list);
    }

    //修改套餐前，获取套餐id进行数据回显
    @ApiOperation("修改套餐前进行数据回显")
    @GetMapping("/{setmealId}")
    public R<SetmealDto> getSetmealDishes(@ApiParam("套餐id")@PathVariable Long setmealId){
        //需要将setmeal对象转为dto,因为dto里面还有菜品关联的数据和套餐分类名称（页面需要）
        Setmeal setmeal = setmealService.getById(setmealId);
        SetmealDto setmealDto = new SetmealDto();
        //拷贝基本数据
        BeanUtils.copyProperties(setmeal,setmealDto);

        //1、条件构造器，根据套餐id查询对应的分类名称
        LambdaQueryWrapper<Category> categoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
        categoryLambdaQueryWrapper.eq(Category::getId,setmeal.getCategoryId());
        Category category = categoryService.getOne(categoryLambdaQueryWrapper);
        //对dto对象赋值分类名称
        setmealDto.setCategoryName(category.getName());


        //2、条件构造器，根据套餐id查询对应菜品集合
        LambdaQueryWrapper<SetmealDish> setmealDishLambdaQueryWrapper = new LambdaQueryWrapper<>();
        setmealDishLambdaQueryWrapper.eq(setmealId!=null,SetmealDish::getSetmealId,setmealId);

        //口味集合
        List<SetmealDish> list = setmealDishService.list(setmealDishLambdaQueryWrapper);
        //把口味集合赋值给dto对象
        setmealDto.setSetmealDishes(list);

        return R.success(setmealDto);
    }



    /**
     * 移动端点击套餐图片查看套餐具体内容
     * 这里返回的是dto 对象，因为前端需要copies这个属性
     * 前端主要要展示的信息是:套餐中菜品的基本信息，图片，菜品描述，以及菜品的份数
     * @param SetmealId
     * @return
     */
    //这里前端是使用路径来传值的，要注意，不然你前端的请求都接收不到，就有点尴尬哈
    @GetMapping("/dish/{id}")
    public R<List<DishDto>> dish(@PathVariable("id") Long SetmealId){
        LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SetmealDish::getSetmealId,SetmealId);
        //获取套餐里面的所有菜品  这个就是SetmealDish表里面的数据
        List<SetmealDish> list = setmealDishService.list(queryWrapper);

        List<DishDto> dishDtos = list.stream().map((setmealDish) -> {
            DishDto dishDto = new DishDto();
            //其实这个BeanUtils的拷贝是浅拷贝，这里要注意一下
            BeanUtils.copyProperties(setmealDish, dishDto);
            //这里是为了把套餐中的菜品的基本信息填充到dto中，比如菜品描述，菜品图片等菜品的基本信息
            Long dishId = setmealDish.getDishId();
            Dish dish = dishService.getById(dishId);
            BeanUtils.copyProperties(dish, dishDto);

            return dishDto;
        }).collect(Collectors.toList());

        return R.success(dishDtos);
    }
}
